home *** CD-ROM | disk | FTP | other *** search
- /***
- * ParseState.c
- *
- * Routines to handle the parse states
- *
- ***/
-
- #include "debug_me.h"
- #include "Exceptions.h"
-
- #include "URLHelperComponent.h"
- #include "URLHelperComponentPrivate.h"
-
- /**
- ** Structs to help with the parsing of the strings - at the moment we have a max of 10
- ** items that can be subbed in one string.
- **/
-
- #define SUB_CHAR '^' // the special replacement character
- #define MAX_PARSE_ITEMS 10 // Max number of "^"s/per string
-
- typedef struct {
- short repID; // ^0 is repID == 0
- unsigned char offset; // Position of the "^" in the string
- unsigned char length; // length of "^0" is 2.
- } parseReplaceItem, *parseReplaceItemPtr;
-
- typedef struct {
- short validItems; // Number of items used.
- parseReplaceItem itemList[MAX_PARSE_ITEMS]; // The items...
- } parseReplaceList, *parseReplaceListPtr;
-
- typedef struct URLHParseState {
- short validItems; // Number of items used
- URLHMirrorListPtr mirrorList; // What mirror list this guy is in...
- Str255 baseURL; // URL string we parsed for this guy
- parseReplaceItem itemList[MAX_PARSE_ITEMS]; // The items
- } URLHParseState, *URLHParseStatePtr, **URLHParseStateHandle;
-
- /**
- ** Local routine definitions
- **/
-
- OSErr PSFindMirrorInList (URLHMirrorListPtr mList, StringPtr aURL,
- URLHParseStatePtr pState);
-
- OSErr PSMatchMirrorToURL (URLHMirrorListPtr mList, URLHMirrorPtr mirror, StringPtr aURL,
- URLHParseStatePtr pState);
-
- OSErr PSParseMirrorName (StringPtr name, parseReplaceListPtr itemList);
-
- OSErr PBParseMatches (StringPtr name, parseReplaceListPtr itemList, StringPtr urlString,
- URLHParseStatePtr pState);
-
- OSErr PSFindString (StringPtr string, short startOffset, short *foundPos,
- StringPtr findString, short findOffset, short findLength);
- /**
- * _URLHelperNewParseState
- *
- * We have a url thing and we now want to find it in our mirror lists
- *
- **/
- pascal ComponentResult _URLHelperNewParseState (Handle storage,
- StringPtr aURL,
- URLHParseStatePtr *pState)
- {
- OSErr theErr;
- URLGlobalsHandle globals = (URLGlobalsHandle) storage;
- URLHMirrorList *mList;
-
- /**
- ** Check the params
- **/
-
- theErr = paramErr;
- require (aURL != 0 && pState != 0, BadParams);
-
- /**
- ** Create a new parse state struct. We will return it if we don't
- ** find a matching url in here...
- **/
-
- *pState = (URLHParseStatePtr) NewPtrClear (sizeof(URLHParseState));
- theErr = MemError ();
- if (theErr == noErr && pState == 0)
- theErr = memFullErr;
- nrequire (theErr, FailedToAllocateParseState);
-
- /**
- ** This is a painful process. Loop over each mirror list and see if there is match
- ** in that mirror list. Of course, since I'm lazy, we break this up into small little
- ** bits!
- **/
-
- mList = (*globals)->mirrorList;
- theErr = errURLHNoMirrorMatch;
-
- while (mList) {
-
- theErr = PSFindMirrorInList (mList, aURL, *pState);
- require (theErr == noErr || theErr == errURLHNoMirrorMatch, FailedToLookAtMirrorList);
- if (theErr == noErr)
- break;
-
- mList = mList -> next;
- }
-
- nrequire (theErr, FailedToFindMirror);
-
- (*pState) -> mirrorList = mList;
- BlockMove (aURL, (*pState)->baseURL, aURL[0]+1);
-
- return noErr;
-
- /**
- ** Errors
- **/
-
- FailedToFindMirror: // Nope -- didn't find it! :(
-
- FailedToLookAtMirrorList: // Something died while looking at the mirror list
-
- DisposPtr ((Ptr) *pState);
-
- FailedToAllocateParseState: // Could not allocate the parse state...
-
- BadParams:
-
- *pState = 0;
- return theErr;
- }
-
- /**
- * PSFindMirrorInList
- *
- * Search through on mirror list looking for a match with a provided URL. Return the
- * resulting parse state if we find it. Again, we hand off the work to another routine
- * to do the true compare...
- *
- **/
- OSErr PSFindMirrorInList (URLHMirrorListPtr mList, StringPtr aURL,
- URLHParseStatePtr pState)
- {
- OSErr theErr;
- URLHMirrorPtr mirror;
-
- mirror = mList -> firstMirror;
- while (mirror) {
-
- theErr = PSMatchMirrorToURL (mList, mirror, aURL, pState);
- require (theErr == noErr || theErr == errURLHNoMirrorMatch, FailedToMatchMirror);
- if (theErr == noErr)
- break;
-
- mirror = mirror -> next;
-
- }
-
- return theErr;
-
- /**
- ** Errors
- **/
-
- FailedToFindOneInList:
-
- FailedToMatchMirror:
-
- return theErr;
- }
-
- /**
- * PSMatchMirrorToURL
- *
- * This is where most of the work gets done. See if the URL we are dealing with will
- * match the mirror specified. Parse out the wild cards as we go along. Ugh city.
- *
- **/
- OSErr PSMatchMirrorToURL (URLHMirrorListPtr mList, URLHMirrorPtr mirror, StringPtr aURL,
- URLHParseStatePtr pState)
- {
- OSErr theErr;
- parseReplaceList mirrorReplace;
- Str255 mirrorName;
-
- /**
- ** First, parse through the mirror list to find the places where we need to do the
- ** replacements...
- **/
-
- theErr = MBGetPString (mList->stringBuffer, mirror->oName, mirrorName);
- nrequire (theErr, FailedToGetMirrorName);
- theErr = PSParseMirrorName (mirrorName, &mirrorReplace);
- nrequire (theErr, FailedToParseMirrorName);
-
- /**
- ** Ok -- next job is to see if the mirror name matches the string...
- **/
-
- theErr = PBParseMatches (mirrorName, &mirrorReplace, aURL, pState);
-
- return theErr;
-
- /**
- ** Errors
- **/
-
- FailedToParseMirrorName: // Ouch -- couldn't parse the mirror name!
-
- FailedToGetMirrorName: // Couldn't extract mirror name from string buffer!
-
- return theErr;
- }
-
- /**
- * PSParseMirrorName
- *
- * This routine will find all the "^n"s in the string we have been given and fill in the
- * replacement item list. Error if there are more than MAX_PARSE_ITEMS in the list.
- *
- **/
- OSErr PSParseMirrorName (StringPtr mirrorName, parseReplaceListPtr list)
- {
- OSErr theErr;
- char *p, *endString;
- short itemsUsed;
-
- /**
- ** Loop through the string looking for our special replacement character, "^".
- **/
-
- itemsUsed = 0;
- p = (char *) &(mirrorName[1]);
- endString = (char *) &(mirrorName[mirrorName[0]]);
- while (p <= endString) {
-
- if (*p == SUB_CHAR) {
- p++;
- require (p <= endString, FailedToGetReplIndex);
- require (itemsUsed < MAX_PARSE_ITEMS, TooManyReplacementItems);
- require ((*p - '0') < MAX_PARSE_ITEMS, BadReplacementChar);
-
- list->itemList[itemsUsed].repID = (*p - '0');
- list->itemList[itemsUsed].offset = p - (char *) &(mirrorName[1]) - 1;
- list->itemList[itemsUsed].length = 2;
- itemsUsed++;
- }
-
- p++;
- }
-
- /**
- ** Put it all together
- **/
-
- list->validItems = itemsUsed;
-
- return noErr;
-
- /**
- ** Errors
- **/
-
- BadReplacementChar:
- theErr = errURLHBadReplChar;
- goto BadReplacement;
-
- TooManyReplacementItems:
- theErr = errURLHTooManyReplacements;
- goto BadReplacement;
-
- FailedToGetReplIndex:
- theErr = errURLHNameEndsWithReplChar;
-
- BadReplacement:
- list -> validItems = 0;
-
- return theErr;
- }
-
- /**
- * PBParseMatches
- *
- * This routine will move through the urlString and see if it matches the given mirror
- * string (with its various parses... This is a true search, so we have to back up and
- * back track when we mess up (it is most ugly).
- *
- * It fills in a parse state with the offsets to the parts of the urlString that
- * match ^0, ^1, etc. etc.
- *
- **/
- OSErr PBParseMatches (StringPtr name, parseReplaceListPtr list, StringPtr urlString,
- URLHParseStatePtr pState)
- {
- OSErr theErr;
- short urlOffset[MAX_PARSE_ITEMS+2];
- short currentItem, index;
- short currentOffset;
- short searchStart[MAX_PARSE_ITEMS+2];
- short searchLength[MAX_PARSE_ITEMS+2];
-
- /**
- ** Figure out what the start and length of each string in the list is..
- **/
-
- index = 0;
- if (list->itemList[0].offset != 0) {
- searchStart[index] = 0;
- searchLength[index] = list->itemList[0].offset;
- index++;
- }
-
- for (currentItem = 0; currentItem < list->validItems; currentItem++) {
-
- searchStart[index] = list->itemList[currentItem].offset
- + list->itemList[currentItem].length;
- if (currentItem+1 < list->validItems) {
- searchLength[index] = list->itemList[currentItem+1].offset
- - searchStart[index];
- } else {
- searchLength[index] = name[0] - searchStart[index];
- }
- index++;
- }
- index --;
- if (searchLength[index] == 0) // Take care of end case...
- index--;
-
- /**
- ** Ok. We now know all the strings we have to search for. So, look for the first,
- ** if we find it then look for the second, etc. etc. If we fail to find the second,
- ** look for the first someplace byond where we found it the first time... etc. etc.
- ** This would have been way simpler to do in SNOBAL, durnit!
- **/
-
- currentItem = 0;
- currentOffset = 0;
-
- while (currentItem <= index
- && currentItem >= 0) {
-
- /**
- ** Search for the current string starting at the current offset...
- **/
-
- theErr = PSFindString (urlString, currentOffset, &(urlOffset[currentItem]),
- name, searchStart[currentItem], searchLength[currentItem]);
- if (theErr != noErr) {
- currentItem--; // Couldn't find the string. Back up...
- if (currentItem >= 0)
- currentOffset = urlOffset[currentItem] + 1;
- } else {
- currentOffset = urlOffset[currentItem]+searchLength[currentItem];
- currentItem++;
- }
-
- }
-
- theErr = noErr;
- if (currentItem < 0)
- theErr = errURLHNoMirrorMatch;
- nrequire (theErr, FailedToDoThisMatch);
-
- /**
- ** Ok -- if we have a good match, then we had better fill in the parse state...
- **/
-
- pState -> validItems = index;
- index = 0;
- if (list->itemList[0].offset == 0) {
- pState->itemList[0].offset = 0;
- pState->itemList[0].length = urlOffset[0] - 1;
- pState->itemList[0].repID = list->itemList[0].repID;
- index++;
- }
-
- for (currentItem = 0; currentItem <= pState->validItems; currentItem++) {
-
- pState->itemList[index].repID = list->itemList[index].repID;
- pState->itemList[index].offset = urlOffset[currentItem] + searchLength[currentItem] - 1;
- if (currentItem+1 <= pState->validItems) {
- pState->itemList[index].length = urlOffset[index+1] - pState->itemList[index].offset;
- } else {
- pState->itemList[index].length = urlString[0] - pState->itemList[index].offset;
- }
- index++;
- }
- pState->validItems = list->validItems;
- return theErr;
-
- /**
- ** Errors
- **/
-
- FailedToDoThisMatch:
-
- pState->validItems = 0;
-
- return theErr;
-
- }
-
- /**
- * PSFindString
- *
- * This dude will find some part of findString in string. It will start the search at offset
- * findOffset. findOffset==0 means the first character in the string.
- *
- **/
- OSErr PSFindString (StringPtr string, short startOffset, short *foundOffset,
- StringPtr findString, short findOffset, short findLength)
- {
- char *p, *endString;
- char *search, *endSearch, *s;
-
- if (findLength == 0)
- return noErr;
-
- p = (char *) string + 1 + startOffset;
- endString = (char *) string + string[0] + 1;
-
- search = (char *) findString + 1 + findOffset;
- endSearch = (char *) findString + 1 + findLength;
- s = search;
-
- while (p < endString) {
-
- if (*s != *p) {
- if (s != search) { // Backtrack if we need to here...
- p -= s - search - 1;
- s = search;
- }
- } else {
- if (s == search)
- *foundOffset = p - (char *) string;
- s++;
- if (s > endSearch)
- return noErr;
- }
- p++;
- }
-
- *foundOffset = 0;
- return genericError;
- }
-
-
- /**
- * _URLHelperDisposeParseState
- *
- * Kill of the struct we use to do the parseing and prelacing...
- *
- **/
- pascal ComponentResult _URLHelperDisposeParseState (Handle storage,
- URLHParseStatePtr pState)
- {
- OSErr theErr;
-
- /**
- ** Make sure the pState isn't zero!
- **/
-
- theErr = paramErr;
- require (pState != 0, BadParams);
-
- DisposePtr ((Ptr) pState);
-
- return noErr;
-
- /**
- ** Errors
- **/
-
- BadParams:
-
- return theErr;
- }
-
- /**
- * _URLHelperGetMirrorRep
- *
- * Given a valid parse state, find a replacement mirror for ourselves and sub in the
- * wild-card strings. Return an error if the caller has indexed past the end of the
- * mirror list.
- *
- * index starts at 1!!!!!
- **/
- pascal ComponentResult _URLHelperGetMirrorRep (Handle storage,
- URLHParseStatePtr pState,
- StringPtr newURL,
- short index)
- {
- OSErr theErr;
- URLGlobalsHandle globals = (URLGlobalsHandle) storage;
- URLHMirrorPtr aMirror;
- Str255 mName;
- parseReplaceList mReplacements;
- char *np, *nend;
- char *mp, *mend;
- char *rp, *rend;
- short index;
- short replacementID;
-
- /**
- ** First job is to make sure that the incomming
- ** parameters are indeed working a-ok.
- **/
-
- theErr = paramErr;
- require (pState != 0 && newURL != 0 && index > 0, BadParams);
-
- /**
- ** First thing to do is loop over the mirrors in the mirror list
- ** and find the one our caller wants to use
- **/
-
- theErr = URLHGetUsableMirror ((*globals)->self, (URLHMirrorListRef) pState->mirrorList,
- (URLHMirrorRef *) &aMirror, index);
- nrequire (theErr, FailedToGetMirror);
-
- /**
- ** Next, parse out the replacement operators...
- **/
-
- theErr = MBGetPString (pState->mirrorList->stringBuffer, aMirror->oName, mName);
- nrequire (theErr, FailedToGetMirrorName);
- theErr = PSParseMirrorName (mName, &mReplacements);
- nrequire (theErr, FailedToGetReplPos);
-
- /**
- ** Now, copy the mirror name into the new url thing, and replace the "^0" with
- ** the appropriate stuff...!!! We replace with a "blank" string if we can't find
- ** the replacemnt ID someplace in base URL guy!
- **/
-
- np = (char *) newURL + 1;
- nend = (char *) newURL + sizeof (Str255);
-
- mp = (char *) mName + 1;
- mend = (char *) mName + 1 + mName[0];
-
- while (mp < mend
- && np < nend) {
-
- if (*mp == SUB_CHAR) { // Ok -- we have to sub something in!
- replacementID = *(++mp) - '0';
-
- index = 0; // Find the repl id info
- while (index < pState->validItems) {
- if (pState->itemList[index].repID == replacementID)
- break;
- index++;
- }
-
- if (index < pState->validItems) { // Got it, sub it in
- rp = (char *) pState->baseURL + 1
- + pState->itemList[index].offset;
- rend = rp + pState->itemList[index].length;
- while (rp < rend && np < nend)
- *np++ = *rp++;
- }
-
- mp++; // Get past rep id.
-
- } else {
- *np++ = *mp++;
- }
-
- }
-
- /**
- ** Fix up the length byte and we are done!
- **/
-
- newURL[0] = np - (char *) newURL - 1;
-
- return noErr;
-
- /**
- ** Errors
- **/
-
- FailedToGetReplPos:
-
- FailedToGetMirrorName:
-
- FailedToGetMirror:
-
- BadParams:
-
- newURL[0] = 0;
-
- return theErr;
- }
-